#!/bin/sh

export E2E_MAJOR_SOURCE_POSTGRES_VERSION="${E2E_MAJOR_SOURCE_POSTGRES_VERSION:-12.16}"
export E2E_MAJOR_TARGET_POSTGRES_VERSION="${E2E_MAJOR_TARGET_POSTGRES_VERSION:-13.12}"
export E2E_STORAGE_CLASS_REFLINK_ENABLED="${E2E_STORAGE_CLASS_REFLINK_ENABLED:-false}"

e2e_use_extensions() {
  true
}

e2e_test_install() {
  CLUSTER_NAME="$(get_sgcluster_name dbops-major-version-upgrade)"
  DBOPS_NAME="$(get_sgdbops_name major-version-upgrade)"

  SOURCE_POSTGIS_VERSION="$(get_latest_version_of_extension postgis "${E2E_MAJOR_SOURCE_POSTGRES_VERSION%.*}" || true)"
  TARGET_POSTGIS_VERSION="$(get_latest_version_of_extension postgis "${E2E_MAJOR_TARGET_POSTGRES_VERSION%.*}" || true)"
  SOURCE_TIMESCALE_VERSION="$(get_latest_version_of_extension timescaledb "${E2E_MAJOR_SOURCE_POSTGRES_VERSION%.*}" || true)"
  TARGET_TIMESCALE_VERSION="$(get_latest_version_of_extension timescaledb "${E2E_MAJOR_TARGET_POSTGRES_VERSION%.*}" || true)"
  SOURCE_PG_REPACK_VERSION="$(get_latest_version_of_extension pg_repack "${E2E_MAJOR_SOURCE_POSTGRES_VERSION%.*}" || true)"
  TARGET_PG_REPACK_VERSION="$(get_latest_version_of_extension pg_repack "${E2E_MAJOR_TARGET_POSTGRES_VERSION%.*}" || true)"
  SOURCE_ADMINPACK_VERSION="$(get_latest_version_of_extension adminpack "$E2E_MAJOR_SOURCE_POSTGRES_VERSION" || true)"

  kubectl create namespace "$CLUSTER_NAMESPACE"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 1
}

reset_cluster() {
  local PODS_RUNNING="$1"
  [ "$#" -lt 1 ] || shift
  reset_cluster_internal "$PODS_RUNNING" false "$@" 
}

reset_cluster_only_pg_repack() {
  local PODS_RUNNING="$1"
  [ "$#" -lt 1 ] || shift
  reset_cluster_internal "$PODS_RUNNING" true "$@" 
}

reset_cluster_internal() {
  local PODS_RUNNING="${1:-3}"
  local ONLY_PG_REPACK="${2:-false}"
  [ "$#" -lt 1 ] || shift
  [ "$#" -lt 1 ] || shift

  remove_cluster_if_exists "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"

  wait_until eval '[ "$(kubectl get pvc -n "$CLUSTER_NAMESPACE" --template "{{ .items | len }}")" = 0 ]'

  if [ "$ONLY_PG_REPACK" = true ]
  then
    create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set-string cluster.pods.persistentVolume.size=2Gi \
      --set-string cluster.postgres.version="$E2E_MAJOR_SOURCE_POSTGRES_VERSION" \
      --set-string cluster.postgres.extensions[0].name=adminpack \
      --set-string cluster.postgres.extensions[0].version="$SOURCE_ADMINPACK_VERSION" \
      --set-string cluster.postgres.extensions[1].name=pg_repack \
      --set-string cluster.postgres.extensions[1].version="$SOURCE_PG_REPACK_VERSION" \
      "$@"
  elif [ -n "$SOURCE_POSTGIS_VERSION" ] && [ "$SOURCE_POSTGIS_VERSION" = "$TARGET_POSTGIS_VERSION" ] \
    && [ -n "$SOURCE_TIMESCALE_VERSION" ] && [ "$SOURCE_TIMESCALE_VERSION" = "$TARGET_TIMESCALE_VERSION" ]
  then
    create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set-string cluster.pods.persistentVolume.size=2Gi \
      --set-string cluster.postgres.version="$E2E_MAJOR_SOURCE_POSTGRES_VERSION" \
      --set-string cluster.postgres.extensions[0].name=adminpack \
      --set-string cluster.postgres.extensions[0].version="$SOURCE_ADMINPACK_VERSION" \
      --set-string cluster.postgres.extensions[1].name=postgis \
      --set-string cluster.postgres.extensions[1].version="$SOURCE_POSTGIS_VERSION" \
      --set-string cluster.postgres.extensions[2].name=timescaledb \
      --set-string cluster.postgres.extensions[2].version="$SOURCE_TIMESCALE_VERSION" \
      --set-string 'configurations.postgresconfig.postgresql\.conf.shared_preload_libraries=pg_stat_statements\, auto_explain\, timescaledb' \
      "$@"
  elif [ -n "$SOURCE_POSTGIS_VERSION" ] && [ "$SOURCE_POSTGIS_VERSION" = "$TARGET_POSTGIS_VERSION" ]
  then
    create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set-string cluster.pods.persistentVolume.size=2Gi \
      --set-string cluster.postgres.version="$E2E_MAJOR_SOURCE_POSTGRES_VERSION" \
      --set-string cluster.postgres.extensions[0].name=adminpack \
      --set-string cluster.postgres.extensions[0].version="$SOURCE_ADMINPACK_VERSION" \
      --set-string cluster.postgres.extensions[1].name=postgis \
      --set-string cluster.postgres.extensions[1].version="$SOURCE_POSTGIS_VERSION" \
      "$@"
  elif [ -n "$SOURCE_TIMESCALE_VERSION" ] && [ "$SOURCE_TIMESCALE_VERSION" = "$TARGET_TIMESCALE_VERSION" ]
  then
    create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set-string cluster.pods.persistentVolume.size=2Gi \
      --set-string cluster.postgres.version="$E2E_MAJOR_SOURCE_POSTGRES_VERSION" \
      --set-string cluster.postgres.extensions[0].name=adminpack \
      --set-string cluster.postgres.extensions[0].version="$SOURCE_ADMINPACK_VERSION" \
      --set-string cluster.postgres.extensions[1].name=timescaledb \
      --set-string cluster.postgres.extensions[1].version="$SOURCE_TIMESCALE_VERSION" \
      --set-string 'configurations.postgresconfig.postgresql\.conf.shared_preload_libraries=pg_stat_statements\, auto_explain\, timescaledb' \
      "$@"
  else
    echo "Extension postgis not found for $(uname -m)"
    create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set-string cluster.pods.persistentVolume.size=2Gi \
      --set-string cluster.postgres.version="$E2E_MAJOR_SOURCE_POSTGRES_VERSION" \
      "$@"
  fi

  wait_pods_running "$CLUSTER_NAMESPACE" "$PODS_RUNNING"
  wait_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"
  switch_cluster_to_first "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"

  if [ "$ONLY_PG_REPACK" != true ] && [ -n "$SOURCE_POSTGIS_VERSION" ] && [ "$SOURCE_POSTGIS_VERSION" = "$TARGET_POSTGIS_VERSION" ]
  then
    kubectl exec -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 -c postgres-util -- psql -q -c "$(cat << 'EOF'
CREATE EXTENSION postgis;
CREATE MATERIALIZED VIEW test AS
 SELECT 'mpoint_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint srsName="EPSG:27582"><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember><gml:pointMember><gml:Point srsName="EPSG:27562"><gml:coordinates>400000,5000000</gml:coordinates></gml:Point></gml:pointMember></gml:MultiPoint>'));
EOF
      )"
  fi

  if [ "$ONLY_PG_REPACK" != true ] && [ -n "$SOURCE_TIMESCALE_VERSION" ] && [ "$SOURCE_TIMESCALE_VERSION" = "$TARGET_TIMESCALE_VERSION" ]
  then
    kubectl exec -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 -c postgres-util -- psql -q -c "$(cat << 'EOF'
CREATE EXTENSION timescaledb;
EOF
      )"
  fi

  # Trigger libLLVM bug. See https://gitlab.com/ongresinc/stackgres/-/issues/1980
  kubectl exec -i -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME"-0 -c postgres-util \
    -- psql -q -c "$(cat << 'EOF'
      DO $$DECLARE r integer;
        BEGIN
          FOR r IN SELECT i FROM generate_series(1, 300) AS i
          LOOP
            EXECUTE 'CREATE TABLE test' || r
              || ' (a integer, b text, c text, d date, e text, f text, g text'
              || ', h timestamp with time zone, i timestamp with time zone'
              || ', j integer, k integer, l integer)';
          END LOOP;
      END$$
EOF
      )"

  remove_cluster_if_exists "$CLUSTER_NAME-for-major-version-upgrade" "$CLUSTER_NAMESPACE"

  if [ "$ONLY_PG_REPACK" != true ] && [ -n "$SOURCE_TIMESCALE_VERSION" ] && [ "$SOURCE_TIMESCALE_VERSION" = "$TARGET_TIMESCALE_VERSION" ]
  then
    create_or_replace_cluster "$CLUSTER_NAME-for-major-version-upgrade" "$CLUSTER_NAMESPACE" 1 \
      --set cluster.create=false \
      --set instanceProfiles=null \
      --set cluster.configurations.sgPostgresConfig=postgresconf-for-major-version-upgrade \
      --set cluster.configurations.sgPoolingConfig=pgbouncerconf-for-major-version-upgrade \
      --set-string 'configurations.postgresconfig.postgresql\.conf.shared_preload_libraries=pg_stat_statements\, auto_explain\, timescaledb' \
      --set-string cluster.postgres.version="$E2E_MAJOR_TARGET_POSTGRES_VERSION"
  else
    create_or_replace_cluster "$CLUSTER_NAME-for-major-version-upgrade" "$CLUSTER_NAMESPACE" 1 \
      --set cluster.create=false \
      --set instanceProfiles=null \
      --set cluster.configurations.sgPostgresConfig=postgresconf-for-major-version-upgrade \
      --set cluster.configurations.sgPoolingConfig=pgbouncerconf-for-major-version-upgrade \
      --set-string cluster.postgres.version="$E2E_MAJOR_TARGET_POSTGRES_VERSION"
  fi

  generate_mock_data "$CLUSTER_NAME"
  check_mock_data_samehost "$CLUSTER_NAME"
  wait_until check_mock_data_replication "$CLUSTER_NAME"

  if kubectl patch sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" --type json \
    --dry-run=server -p "$(cat << EOF
[
  {"op":"replace","path":"/spec/postgres/version","value":"$E2E_MAJOR_TARGET_POSTGRES_VERSION"},
  {"op":"replace","path":"/spec/configurations/sgPostgresConfig","value":"postgresconf-for-major-version-upgrade"}
]
EOF
        )" >/dev/null 2>&1
  then
    success "Can change SGCluster postgres version directly."
  else
    fail "Can not change SGCluster postgres version directly."
  fi
}

check_major_version_upgrade() {
  assert_dbops_running "$DBOPS_NAME" "$CLUSTER_NAMESPACE"

  wait_until eval '[ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" -o json \
    | jq --argjson timestamp "$(date +%s)" ".metadata.annotations[\"stackgres.io/lockTimeout\"] | . // \"0\" | tonumber - \$timestamp")" -gt 0 ]'
  if kubectl patch sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" --type json \
    -p '[{"op":"replace","path":"/spec/metadata","value":{"annotations":{"allResources":{"'"$(random_string)"'": "'"$(random_string)"'"}}}}]' \
    >/dev/null 2>&1
  then
    fail "Cluster has been updated while locked."
  else
    success "Cluster has not been updated while locked."
  fi

  assert_dbops_completion "$DBOPS_NAME" "$CLUSTER_NAMESPACE" "$((E2E_TIMEOUT * 2))"

  if [ "$(kubectl get -n "$CLUSTER_NAMESPACE" job \
    -l "stackgres.io/dbops-name=$DBOPS_NAME,stackgres.io/db-ops=true" \
    -o name 2>/dev/null | wc -l)" = 1 ]
  then
    success "major version upgrade job was not removed after completion."
  else
    fail "major version upgrade job was removed after completion."
  fi

  if [ "$(kubectl get -n "$CLUSTER_NAMESPACE" sgcluster "$CLUSTER_NAME" \
    --template '{{ .spec.postgres.version }}')" = "$E2E_MAJOR_TARGET_POSTGRES_VERSION" ]
  then
    success "cluster postgres version has been updated."
  else
    fail "cluster postgres version has not been updated."
  fi

  check_mock_data_samehost "$CLUSTER_NAME"
  wait_until check_mock_data_replication "$CLUSTER_NAME"
}

check_major_version_upgrade_check() {
  assert_dbops_running "$DBOPS_NAME" "$CLUSTER_NAMESPACE"

  wait_until eval '[ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" -o json \
    | jq --argjson timestamp "$(date +%s)" ".metadata.annotations[\"stackgres.io/lockTimeout\"] | . // \"0\" | tonumber - \$timestamp")" -gt 0 ]'
  if kubectl patch sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" --type json \
    -p '[{"op":"replace","path":"/spec/metadata","value":{"annotations":{"allResources":{"'"$(random_string)"'": "'"$(random_string)"'"}}}}]' \
    >/dev/null 2>&1
  then
    fail "Cluster has been updated while locked."
  else
    success "Cluster has not been updated while locked."
  fi

  assert_dbops_completion "$DBOPS_NAME" "$CLUSTER_NAMESPACE" "$((E2E_TIMEOUT * 2))"

  if [ "$(kubectl get -n "$CLUSTER_NAMESPACE" job \
    -l "stackgres.io/dbops-name=$DBOPS_NAME,stackgres.io/db-ops=true" \
    -o name 2>/dev/null | wc -l)" = 1 ]
  then
    success "major version upgrade job was not removed after completion."
  else
    fail "major version upgrade job was removed after completion."
  fi

  if [ "$(kubectl get -n "$CLUSTER_NAMESPACE" sgcluster "$CLUSTER_NAME" \
    --template '{{ .spec.postgres.version }}')" = "$E2E_MAJOR_SOURCE_POSTGRES_VERSION" ]
  then
    success "cluster postgres version has not been updated."
  else
    fail "cluster postgres version has been updated."
  fi

  check_mock_data_samehost "$CLUSTER_NAME"
  wait_until check_mock_data_replication "$CLUSTER_NAME"
  if kubectl exec -ti -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME-0" -c patroni -- psql -q -w -h localhost -p 5432 -c 'SELECT 1'
  then
    fail "was possible to connect to the cluster without password"
  else
    success "was not possible to connect to the cluster without password"
  fi
}
